package com.hmall.search.service.impl;

import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.service.ISearchService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
@AllArgsConstructor
public class SearchServiceImpl implements ISearchService {

    private final ElasticsearchClient esClient;


    @Override
    public PageDTO<ItemDoc> search(ItemPageQuery query) throws IOException {
        SearchResponse<ItemDoc> response = esClient.search(builder -> builder
                        .index("items")
                        .query(qb -> qb.bool(bb -> {
                                            if (ObjectUtil.isNotEmpty(query.getKey())) {
                                                bb.must(mb -> mb.match((m -> m.field("name").query(query.getKey()))));
                                            }
                                            if (ObjectUtil.isNotEmpty(query.getCategory())) {
                                                bb.filter(fb -> fb.term(tb -> tb.field("category").value(query.getCategory())));
                                            }
                                            if (ObjectUtil.isNotEmpty(query.getBrand())) {
                                                bb.filter(fb -> fb.term(tb -> tb.field("brand").value(query.getBrand())));
                                            }
                                            if (ObjectUtil.isNotEmpty(query.getMinPrice())) {
                                                bb.filter(fb -> fb.range(rb -> rb.field("price").gte(JsonData.of(query.getMinPrice()))));
                                            }
                                            if (ObjectUtil.isNotEmpty(query.getMaxPrice())) {
                                                bb.filter(fb -> fb.range(rb -> rb.field("price").lte(JsonData.of(query.getMaxPrice()))));
                                            }
                                            return bb;
                                        }
                                )
                        )
                        // 按字段排序
                        .sort(sb -> sb.field(fsb -> {
                            if (ObjectUtil.isEmpty(query.getSortBy())) {
                                fsb.field("_score").order(SortOrder.Desc);
                            } else {
                                fsb.field(query.getSortBy())
                                        .order(query.getIsAsc() ? SortOrder.Asc : SortOrder.Desc);
                            }
                            return fsb;
                        }))
                        .from(query.getPageSize() * (query.getPageNo() - 1))
                        .size(query.getPageSize())
                        .highlight(hb -> hb.fields("name", hfb -> hfb.preTags("<em style='color:red'>").postTags("</em>")))
                , ItemDoc.class);
        // 封装结果
        PageDTO<ItemDoc> dto = new PageDTO<>();
        // 总数量
        dto.setTotal(response.hits().total().value());
        // 数据列表
        List<ItemDoc> list = new ArrayList<>();
        List<Hit<ItemDoc>> hits = response.hits().hits();
        for (Hit<ItemDoc> hit : hits) {
            ItemDoc source = hit.source();
            // 获取高亮的
            Map<String, List<String>> map = hit.highlight();
            if (ObjectUtil.isNotEmpty(map)) {
                List<String> nameList = map.get("name");
                if (ObjectUtil.isNotEmpty(nameList)) {
                    source.setName(nameList.get(0));
                }
            }
            // 添加数据
            list.add(source);
        }
        dto.setList(list);

        return dto;
    }
}